package com.xiashitech.agent.rule.usermatch.inst;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.auto.service.AutoService;
import com.xiashitech.agent.config.StartConfig;
import com.xiashitech.agent.dto.UserRequest;
import com.xiashitech.agent.rule.usermatch.base.UserInfoMatchRule;
import com.xiashitech.agent.utils.JsonUtil;
import com.xiashitech.interfaces.agent.dto.AgentConfigDTO;

import java.lang.reflect.Modifier;
import java.util.*;

/**
 * 获取spring的request里的userid,userid直接存储获通过一层对象属性存储
 * @param <REQUEST>
 */
//@AutoService(UserInfoMatchRule.class)
public class XSSpringControllerUserMatch<REQUEST> implements UserInfoMatchRule<REQUEST>{
    @Override
    public UserRequest extractUserInfo(REQUEST request) {
        if (!(request.getClass().getName().equals("org.springframework.web.context.request.ServletWebRequest"))) {
            return UserRequest.builder().build();
        }
        UserRequest userRequest = UserRequest.builder().requestDate(String.valueOf(new Date().getTime())).build();

        try {
            Object httpRequest = request.getClass().getMethod("getRequest").invoke(request);
            if(!Modifier.isPublic(httpRequest.getClass().getModifiers())) {
                return UserRequest.builder().build();
            }
            Object httpSession = httpRequest.getClass().getMethod("getSession",new Class[]{boolean.class}).invoke(httpRequest,false);
            if (httpSession != null) {
                Object sessionId = httpSession.getClass().getMethod("getId").invoke(httpSession);
                if(sessionId != null) {
                    userRequest.setSessionId(sessionId.toString());
                }
                List<String> usernamekeys = AgentConfigDTO.getConfig().getUsernamekey();
                if (usernamekeys != null) {
                    usernamekeys.forEach(userkey -> {
                        try {
                            Enumeration<String> attributeNames = (Enumeration<String>)httpSession.getClass().getMethod("getAttributeNames").invoke(httpSession);
                            String realUserkey = "";
                            while (attributeNames.hasMoreElements()) {
                                String findUserkey = attributeNames.nextElement();
                                if (userkey.equalsIgnoreCase(findUserkey)) {
                                    realUserkey = findUserkey;
                                    break;
                                }
                            }
                            if (!"".equals(realUserkey)) {
                                Object userInfo = httpSession.getClass().getMethod("getAttribute",new Class[]{String.class}).invoke(httpSession,realUserkey);
                                if (userInfo instanceof String && !JsonUtil.isJson((String) userInfo)) {
                                    userRequest.setUserid((String) userInfo);
                                } else {
                                    ObjectNode objectNode = JsonUtil.getJsonNode(userInfo);
                                    List<String> userids = AgentConfigDTO.getConfig().getUserid();
                                    userids.forEach(userid -> {
                                        JsonNode jsonNode = objectNode.findValue(userid);
                                        if(jsonNode != null) {
                                            if(jsonNode.isValueNode()) {
                                                userRequest.setUserid(jsonNode.asText());
                                            }
                                        }
                                    });
                                }
                            }
                        } catch (Throwable e) {
                            // StartConfig.throwableStackPrinter(e);
                        }
                    });
                }
            }
            if (userRequest.getUserid() == null || userRequest.getUserid().isEmpty()) {
                Object requestAttributes = Class.forName("org.springframework.web.context.request.RequestContextHolder").getMethod("getRequestAttributes").invoke(null);
                Object httpServletRequest = requestAttributes.getClass().getMethod("getRequest").invoke(requestAttributes);
                getUserInfo(userRequest,httpServletRequest);
            }
        } catch (Throwable e) {
            StartConfig.throwableStackPrinter(e);
        }
        return userRequest;
    }

    private void getUserInfo(UserRequest userRequest, Object httpServletRequest) {
        try {
            Object httpSession = httpServletRequest.getClass().getMethod("getSession",new Class[]{boolean.class}).invoke(httpServletRequest,false);
            List<String> usernamekeys = AgentConfigDTO.getConfig().getUsernamekey();
            if (httpSession != null) {
                Object sessionId = httpSession.getClass().getMethod("getId").invoke(httpSession);
                if(sessionId != null) {
                    userRequest.setSessionId(sessionId.toString());
                }
                if (usernamekeys != null) {
                    usernamekeys.forEach(userkey -> {
                        try {
                            Enumeration<String> attributeNames = (Enumeration<String>)httpSession.getClass().getMethod("getAttributeNames").invoke(httpSession);
                            String realUserkey = "";
                            while (attributeNames.hasMoreElements()) {
                                String findUserkey = attributeNames.nextElement();
                                if (userkey.equalsIgnoreCase(findUserkey)) {
                                    realUserkey = findUserkey;
                                    break;
                                }
                            }
                            if (!"".equals(realUserkey)) {
                                Object userInfo = httpSession.getClass().getMethod("getAttribute",new Class[]{String.class}).invoke(httpSession,realUserkey);
                                if (userInfo instanceof String && !JsonUtil.isJson((String) userInfo)) {
                                    userRequest.setUserid((String) userInfo);
                                } else {
                                    ObjectNode objectNode = JsonUtil.getJsonNode(userInfo);
                                    List<String> userids = AgentConfigDTO.getConfig().getUserid();
                                    userids.forEach(userid -> {
                                        JsonNode jsonNode = objectNode.findValue(userid);
                                        if(jsonNode != null) {
                                            if(jsonNode.isValueNode()) {
                                                userRequest.setUserid(jsonNode.asText());
                                            }
                                        }
                                    });
                                }
                            }
                        } catch (Throwable e) {
                            StartConfig.throwableStackPrinter(e);
                        }
                    });
                }
            }
        } catch (Throwable e) {
            StartConfig.throwableStackPrinter(e);
        }
    }

    @Override
    public Integer getOrder() {
        return 0;
    }
}
